/*
 * SocketPair.cpp
 *
 *  Created on: 2012-1-10
 *      Author: terry
 */

#include "SocketPair.h"
#include <algorithm>

#undef max

#ifdef WIN32

#else
	#include <signal.h>

	#include <unistd.h>
	#include <stdlib.h>
	#include <string.h>
	#include <netdb.h>
	#include <arpa/inet.h>
	#include <fcntl.h>
	#include <sys/ioctl.h>
	#include <net/if.h>
	#include <netinet/tcp.h>

	#ifndef MAX_PATH
	#define MAX_PATH    256
	#endif //MAX_PATH
#endif // WIN32



namespace util
{


SocketPair::SocketPair() :
        m_serverSocket(),
        m_clientSocket()
{

}

SocketPair::~SocketPair()
{
    close();
}


bool SocketPair::open()
{
	comn::Socket listenSocket;
    if (!listenSocket.open(SOCK_STREAM))
    {
        return false;
    }

    comn::SockAddr addr("127.0.0.1", 0);
    listenSocket.bind(addr);
    listenSocket.listen();

    bool done = makeConnection(listenSocket);

    listenSocket.close();
    return done;
}

void SocketPair::close()
{
    m_clientSocket.close();
    m_serverSocket.close();
}

bool SocketPair::isOpen() const
{
    return m_clientSocket.isOpen();
}

socket_t SocketPair::getPeerHandle() const
{
    return m_serverSocket.getHandle();
}

socket_t SocketPair::getHandle() const
{
    return m_clientSocket.getHandle();
}

void SocketPair::makeReadable()
{
    int byte = 0x99;
    m_serverSocket.send((char*)&byte, sizeof(int), 0);
}

void SocketPair::clearReadable()
{
    const int BUFFER_MAX = 100;
    char buffer[BUFFER_MAX] = {0};
    int ret = m_clientSocket.receive(buffer, sizeof(buffer));
    while (ret == BUFFER_MAX)
    {
        ret = m_clientSocket.receive(buffer, sizeof(buffer));
    }
}

bool SocketPair::makeConnection(comn::Socket& listenSocket)
{
    if (!m_clientSocket.open(SOCK_STREAM))
    {
        return false;
    }

    bool done = false;
    m_clientSocket.setNonblock(true);
    comn::SockAddr addr = listenSocket.getSockName();
    m_clientSocket.connect(addr);

    if (listenSocket.checkReadable(200))
    {
        m_serverSocket = listenSocket.accept(addr);
        done = m_serverSocket.isOpen();
    }
    else
    {
        m_clientSocket.close();
    }

    return done;
}

bool SocketPair::checkReadable(socket_t fd, long millsec)
{
    fd_set rset;
    FD_ZERO(&rset);
    FD_SET(fd, &rset);
    FD_SET(getHandle(), &rset);

    socket_t maxFd = std::max(fd, getHandle());

    timeval* ptv = NULL;
    timeval tv = { millsec / 1000, (int)(millsec % 1000) * 1000 };
    ptv = (millsec >= 0) ? (&tv) : NULL;

    int ret = select((int) maxFd + 1, &rset, NULL, NULL, ptv);
    if (ret <= 0)
    {
        return false;
    }

    if (FD_ISSET(getHandle(), &rset))
    {
        clearReadable();
    }

    return FD_ISSET(fd, &rset) > 0;
}

bool SocketPair::checkWritable(socket_t fd, long millsec)
{
    fd_set rset;
    FD_ZERO(&rset);
    FD_SET(getHandle(), &rset);

    fd_set wset;
    FD_ZERO(&wset);
    FD_SET(fd, &wset);

    socket_t maxFd = std::max(fd, getHandle());

    timeval* ptv = NULL;
    timeval tv = { millsec / 1000, (int)(millsec % 1000) * 1000 };
    ptv = (millsec >= 0) ? (&tv) : NULL;

    int ret = select((int) maxFd + 1, &rset, &wset, NULL, ptv);
    if (ret <= 0)
    {
        return false;
    }

    if (FD_ISSET(getHandle(), &rset))
    {
        clearReadable();
    }
    return FD_ISSET(fd, &wset) > 0;
}



}
